Coding conventions
==================
Introduction
------------
The coding conventions used in SpinalHDL are the same as the ones documented in the `Scala Style Guide `_.
Some additional practical details and cases are explained in next pages.
class vs case class
-------------------
When you define a ``Bundle`` or a ``Component``, it is preferable to declare it as a case class.
The reasons are:
* It avoids the use of ``new`` keywords. Never having to use it is better than sometimes, under some conditions.
* A ``case class`` provides a ``clone`` function. This is useful in SpinalHDL when there is a need to clone a ``Bundle``, for example, when you define a new ``Reg`` or a new ``Stream`` of some kind.
* Construction parameters are directly visible from outside.
[case] class
^^^^^^^^^^^^
All classes names should start with a uppercase letter
.. code-block:: scala
class Fifo extends Component {
}
class Counter extends Area {
}
case class Color extends Bundle {
}
companion object
^^^^^^^^^^^^^^^^
A `companion object `_ should start with an uppercase letter.
.. code-block:: scala
object Fifo {
def apply(that: Stream[Bits]): Stream[Bits] = {...}
}
object MajorityVote {
def apply(that: Bits): UInt = {...}
}
An exception to this rule is when the companion object is used as a function (only ``apply`` inside), and these ``apply`` functions don't generate hardware:
.. code-block:: scala
object log2 {
def apply(value: Int): Int = {...}
}
function
^^^^^^^^
A function should always start with a lowercase letter:
.. code-block:: scala
def sinTable = (0 until sampleCount).map(sampleIndex => {
val sinValue = Math.sin(2 * Math.PI * sampleIndex / sampleCount)
S((sinValue * ((1 << resolutionWidth) / 2 - 1)).toInt, resolutionWidth bits)
})
val rom = Mem(SInt(resolutionWidth bit), initialContent = sinTable)
instances
^^^^^^^^^
Instances of classes should always start with a lowercase letter:
.. code-block:: scala
val fifo = new Fifo()
val buffer = Reg(Bits(8 bits))
if / when
^^^^^^^^^
Scala ``if`` and SpinalHDL ``when`` should normally be written in the following way:
.. code-block:: scala
if(cond) {
...
} else if(cond) {
...
} else {
...
}
when(cond) {
...
}.elseWhen(cond) {
...
}.otherwise {
...
}
Exceptions could be:
* It's fine to omit the dot before ``otherwise``.
* It's fine to compress an ``if``\ /\ ``when`` statement onto a single line if it makes the code more readable.
switch
^^^^^^
SpinalHDL ``switch`` should normally be written in the following way:
.. code-block:: scala
switch(value) {
is(key) {
}
is(key) {
}
default {
}
}
It's fine to compress an ``is``\ /\ ``default`` statement onto a single line if it makes the code more readable.
Parameters
^^^^^^^^^^
Grouping parameters of a ``Component``/``Bundle`` inside a case class is generally welcome because:
* Easier to carry/manipulate to configure the design
* Better maintainability
.. code-block:: scala
case class RgbConfig(rWidth: Int, gWidth: Int, bWidth: Int) {
def getWidth = rWidth + gWidth + bWidth
}
case class Rgb(c: RgbConfig) extends Bundle {
val r = UInt(c.rWidth bit)
val g = UInt(c.gWidth bit)
val b = UInt(c.bWidth bit)
}
But this should not be applied in all cases. For example: in a FIFO, it doesn't make sense to group the ``dataType`` parameter with the ``depth`` parameter of the fifo because, in general, the ``dataType`` is something related to the design, while the ``depth`` is something related to the configuration of the design.
.. code-block:: scala
class Fifo[T <: Data](dataType: T, depth: Int) extends Component {
}